#include "info/cktinfo.h"
#include "util/util.h"
#include "base/cktname.h"

#include <iostream>

using std::cout;
using std::endl;

static bool match( CktInfo & in , CktName & n )
{
   unsigned pinum = in._ppiFlag - 1;
   unsigned dffnum = in._andFlag - in._ppiFlag ;
   unsigned ponum = in._po.size() - dffnum ;

   if( n.piName.size() != pinum )return false;
   if( n.poName.size() != ponum )return false;
   if( n.latchName.size() != dffnum )return false;
   return true;
}

//--- processing the circuit to be combination
static void comb( CktInfo & in , CktName & n )
{
   assert( iomatching( in , n ) );

   vector<string> npo;
   for( unsigned i = 0 ; i < n.latchName.size() ; ++ i )
      n.piName.push_back( n.latchName[i] ),
      npo.push_back( n.latchName[i] + "_in");
   for( unsigned i = 0 ; i < n.poName.size() ; ++ i )
      npo.push_back( n.poName[i] );
   std::swap( npo , n.poName );

   in._ppiFlag = in._andFlag;
   n.latchName.clear();

}

static void marking( const StrashAIG & in , uint8_t * m , unsigned t )
{
   if( m[t] ) return ;
   m[t]=true;
   if( t < in._andFlag ) return ;
   marking( in , m , var( in[t].fanin[0] ) );
   marking( in , m , var( in[t].fanin[1] ) );
}
static AigLit construct( const StrashAIG & in , AigLit t , AigLit * lut , StrashAIG & out )
{
   if( var( t ) == 0 ) return t;
   if( lut[ var(t) ] == 0 )
      lut[ var(t) ] = out.createAND( construct( in , in[var(t)].fanin[0] , lut , out ) , 
                                     construct( in , in[var(t)].fanin[1] , lut , out ) );
   return lut[ var(t) ] ^ sign(t);
}
//selecting a node in the circuit and produce the sub circuit and constructing as output 
//
static void select ( const CktInfo & in , AigLit target , StrashAIG & out)
{
   AigLit lut[in.sz];
   memset( lut , 0 , sizeof(AigLit)*in.sz);
   uint8_t mark[in.size()];
   memset( mark,0,sizeof(uint8_t)*in.sz);
   
   // create base
   {
      marking( in , mark , var(target) );
      for( unsigned i = 1 , j=1  ; i < in._andFlag; ++ i )
      {
         if( mark[i] == false ) continue;

         out.createBase();
         lut[i] = toAigLit( j++ , 0 );
      }
      out._andFlag = out._ppiFlag = out.sz;
   }

   // recursively creation
   out._po.push( construct( in , target , lut , out) );
}
static AigLit target( const StrashAIG & ckt , bool internal , int idx )
{
   if( internal )
   {
      unsigned var = ((idx > 0)?idx:-idx);
      if( var >= ckt.sz ){ cout << "idx excess [ 1 - " << ckt.sz-1 << "]"<<endl; exit(1);}
      return toAigLit( var , idx < 0 );
   }else
   {
      if( ((unsigned)idx) >= ckt._po.sz ){cout<< "idx excess [ 0 - " << ckt._po.sz-1 <<"]"<<endl;exit(1);}
      return ckt._po[idx];
   }
}
int main( int argc , const char ** argv  )
{
   ArgAnalyzer arg( "do <infile:aig> <PoIdx:int> <outfile:aig> [-internal]" , argc , argv );

   StrashAIG ckt;
   CktName   name;
   

   {
      CktInfo in;
      in.read_aig( arg[0].c_str() , & name );
      comb( in , name );
      
      AigLit t = target( in , arg["-internal"].setted , atoi( arg[1].c_str() ) );
      select( in , t, ckt );
   }
   ckt.report();
   ckt.write_aig( arg[2].c_str());
   return 0;
}
